<template>
  <div>
    <el-input v-model="inputValue" placeholder="请选择" @focus="handleInputFocus" @input="handleInput" @search="handleInputSearch">
      <template slot="prefix">
        <div v-for="(tag, index) in tags" :key="index" class="input-tag">
          {{ tag.label }}({{tag.level}})
          <i class="ivu-icon ivu-icon-close" @click="handleTagClose(tag)"></i>
        </div>
      </template>
      <template slot="suffix">
        <i class="el-input__icon el-icon-arrow-up" :class="{'is-reverse': visible}" @click="handleArrowClick"></i>
      </template>
    </el-input>
    <el-popover
        v-model="visible"
        ref="popover"
        popper-class="tree-popover"
        trigger="click"
        placement="bottom-start"
        width="300"
        @show="handlePopoverShow"
        @shown="handlePopoverShown"
        @hide="handlePopoverHide"
        @hidden="handlePopoverHidden">
      <div class="tree-popover-content">
        <el-tree
            ref="tree"
            :data="data"
            :props="treeProps"
            :check-strictly="true"
            :default-checked-keys="checkedKeys"
            :expand-on-click-node="false"
            node-key="id"
            show-checkbox
            @check-change="handleCheckChange"
            @node-click="handleNodeClick"/>
      </div>
    </el-popover>
  </div>
</template>

<script>
export default {
  name: 'CategoryTreeSelect',
  props: {
    data: {
      type: Array,
      default: () => []
    },
    value: {
      type: Array,
      default: () => []
    },
    treeProps: {
      type: Object,
      default: () => ({
        children: 'children'
      })
    },
    showLevel: {
      type: Number,
      default: () => 0
    }
  },
  data () {
    return {
      visible: false,
      inputValue: '',
      checkedKeys: this.value,
      tags: []
    }
  },
  watch: {
    value (value) {
      this.checkedKeys = value
    },
    checkedKeys (checkedKeys) {
      this.updateTags()
      this.$emit('input', checkedKeys)
    }
  },
  computed: {
    selectedCategories () {
      const categories = []
      this.tags.forEach(tag => {
        categories.push(tag.label)
      })
      return categories
    }
  },
  created () {
    this.checkedKeys = this.value
    this.updateTags()
  },
  methods: {
    handleInput () {
      if (!this.visible) {
        this.visible = true
      }
    },
    handleInputSearch () {
      const keyword = this.inputValue.trim()
      if (keyword) {
        this.$refs.tree.filter(keyword)
      } else {
        this.$refs.tree.clearFilter()
        this.$refs.tree.setCheckedKeys(this.checkedKeys)
      }
    },
    handleInputFocus () {
      this.visible = true
    },
    handleArrowClick () {
      if (this.visible) {
        this.$refs.popover.hide()
      } else {
        this.$refs.popover.show()
      }
    },
    handlePopoverShow () {
      this.$refs.tree.setCheckedKeys(this.checkedKeys)
    },
    handlePopoverShown () {
      this.$refs.tree.$el.focus()
    },
    handlePopoverHide () {
      this.inputValue = ''
    },
    handlePopoverHidden () {
      this.$refs.tree.setCurrentKey(this.checkedKeys[this.checkedKeys.length - 1])
    },
    handleCheckChange (checkedKeys, { checkedNodes, halfCheckedNodes }) {
      this.checkedKeys = checkedKeys
    },
    handleNodeClick (node) {
      // Add or remove tag
      const index = this.tags.findIndex(tag => tag.id === node.id)
      if (index > -1) {
        this.tags.splice(index, 1)
      } else {
        this.tags.push({
          label: node.label,
          level: node.level
        })
      }
      // Update value with checked nodes
      const checkedNodes = this.$refs.tree.getCheckedNodes()
      const selectedKeys = []
      checkedNodes.forEach(node => {
        selectedKeys.push(node.id)
      })
      this.checkedKeys = selectedKeys
      // Close popover
      this.visible = false
    },
    handleTagClose (tag) {
      const index = this.tags.findIndex(item => item.id === tag.id)
      if (index > -1) {
        this.tags.splice(index, 1)
        this.updateCheckedKeys()
      }
    },
    updateCheckedKeys () {
      let selectedKeys = []
      const lastTag = this.tags[this.tags.length - 1]
      if (lastTag) {
        const ancestors = this.getAncestors(lastTag)
        ancestors.push(lastTag)
        selectedKeys = ancestors.map(node => node.id)
      }
      this.checkedKeys = selectedKeys
    },
    updateTags () {
      const checkedNodes = this.$refs.tree.getCheckedNodes({ includeHalfChecked: true })
      const tags = []
      checkedNodes.forEach(node => {
        if (node.children && node.children.length > 0) {
          // Do not show parent node if any child node is selected
          return
        }
        if (node.level === 0) {
          // Do not show root node
          return
        }
        if (this.showLevel && node.level > this.showLevel) {
          // Show only nodes up to selected level
          return
        }
        tags.push({
          label: node.label,
          level: node.level
        })
      })
      this.tags = tags
    },
    getAncestors (node) {
      const ancestors = []
      let parent = this.$refs.tree.getNode(node.parent.id)
      while (parent) {
        ancestors.unshift(parent)
        parent = this.$refs.tree.getNode(parent.parent.id)
      }
      return ancestors
    }
  }
}
</script>

<style scoped>
.input-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 22px;
  padding: 0 7px;
  margin-right: 5px;
  font-size: 12px;
  color: #fff;
  background-color: #ff9900;
  border-radius: 4px;
}
.input-tag:hover {
  cursor: pointer;
}
.el-popover__title {
  display: none !important;
}
.tree-popover {
  border-radius: 4px;
}
.tree-popover-content {
  max-height: 300px;
  overflow-y: auto;
  padding: 10px;
}
</style>